package config

import (
	"fmt"

	"github.com/spf13/viper"
)

type Config struct {
	App     AppConfig     `mapstructure:"app"`
	MySQL   MySQLConfig   `mapstructure:"mysql"`
	MongoDB MongoDBConfig `mapstructure:"mongodb"`
	ES      ESConfig      `mapstructure:"elasticsearch"`
	MinIO   MinIOConfig   `mapstructure:"minio"`
	Queue   QueueConfig   `mapstructure:"queue"`
	Redis   RedisConfig   `mapstructure:"redis"`
	Log     LogConfig     `mapstructure:"log"`
}

type AppConfig struct {
	Name     string `mapstructure:"name"`
	Version  string `mapstructure:"version"`
	Mode     string `mapstructure:"mode"`
	Port     int    `mapstructure:"port"`
	TimeZone string `mapstructure:"timezone"`
}

type MySQLConfig struct {
	Host     string `mapstructure:"host"`
	Port     int    `mapstructure:"port"`
	Username string `mapstructure:"username"`
	Password string `mapstructure:"password"`
	Database string `mapstructure:"database"`
	Params   string `mapstructure:"params"`
}

type MongoDBConfig struct {
	URI       string `mapstructure:"uri"`
	Databases struct {
		News      string `mapstructure:"news"`
		Ecommerce string `mapstructure:"ecommerce"`
		Social    string `mapstructure:"social"`
	} `mapstructure:"databases"`
}

type ESConfig struct {
	Addresses []string `mapstructure:"addresses"`
	Username  string   `mapstructure:"username"`
	Password  string   `mapstructure:"password"`
}

type MinIOConfig struct {
	Endpoint  string `mapstructure:"endpoint"`
	AccessKey string `mapstructure:"access_key"`
	SecretKey string `mapstructure:"secret_key"`
	UseSSL    bool   `mapstructure:"use_ssl"`
	Buckets   struct {
		News     string `mapstructure:"news"`
		Product  string `mapstructure:"product"`
		Social   string `mapstructure:"social"`
		Document string `mapstructure:"document"`
		Backup   string `mapstructure:"backup"`
	} `mapstructure:"buckets"`
}

type QueueConfig struct {
	Type     string `mapstructure:"type"` // rabbitmq, kafka
	RabbitMQ struct {
		URI      string `mapstructure:"uri"`
		Exchange string `mapstructure:"exchange"`
	} `mapstructure:"rabbitmq"`
	Kafka struct {
		URI     string `mapstructure:"uri"`
		GroupID string `mapstructure:"group_id"`
	} `mapstructure:"kafka"`
	Queues struct {
		Task  string `mapstructure:"task"`
		File  string `mapstructure:"file"`
		Index string `mapstructure:"index"`
	} `mapstructure:"queues"`
}

type RedisConfig struct {
	Addr     string `mapstructure:"addr"`
	Password string `mapstructure:"password"`
	DB       int    `mapstructure:"db"`
}

type LogConfig struct {
	Level      string `mapstructure:"level"`
	FilePath   string `mapstructure:"file_path"`
	MaxSize    int    `mapstructure:"max_size"`    // megabytes
	MaxBackups int    `mapstructure:"max_backups"` // number of backups
	MaxAge     int    `mapstructure:"max_age"`     // days
	Compress   bool   `mapstructure:"compress"`
}

var GlobalConfig Config

// LoadConfig loads configuration from file
func LoadConfig(configPath string) (*Config, error) {
	if configPath == "" {
		configPath = "./config"
	}

	viper.SetConfigName("config")
	viper.AddConfigPath(configPath)
	viper.SetConfigType("yaml")

	// Set default values
	viper.SetDefault("app.name", "data-center")
	viper.SetDefault("app.version", "1.0.0")
	viper.SetDefault("app.mode", "development")
	viper.SetDefault("app.port", 8080)
	viper.SetDefault("app.timezone", "Asia/Shanghai")

	// Read the config file
	err := viper.ReadInConfig()
	if err != nil {
		return nil, fmt.Errorf("failed to read config file: %w", err)
	}

	// Unmarshal the config
	err = viper.Unmarshal(&GlobalConfig)
	if err != nil {
		return nil, fmt.Errorf("failed to unmarshal config: %w", err)
	}

	return &GlobalConfig, nil
}

// GetDSN returns the MySQL DSN
func (c *MySQLConfig) GetDSN() string {
	dsn := fmt.Sprintf("%s:%s@tcp(%s:%d)/%s",
		c.Username, c.Password, c.Host, c.Port, c.Database)

	if c.Params != "" {
		dsn = fmt.Sprintf("%s?%s", dsn, c.Params)
	}

	return dsn
}
